import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { Observable } from 'rxjs';

@Injectable()
export class HttpRequestService {
    private readonly baseUrl: string = 'workflow-example';

    constructor(
        private httpClient: HttpClient
    ) { }

    /**
     * Combines the provided base url and relative url. 
     * Does NOT use HttpInterceptor to achieve this goal because we want to 
     * make the code logic clear and in one place.
     * @param baseUrl The base url for current http request.
     * @param url The relative url string.
     * @returns The full url. 
     */
    combineUrl(baseUrl: string, url: string): string {
        if (baseUrl && baseUrl !== '') {
            // Converts the input url to lower case just in case.
            // url = url.toLowerCase();

            // Checks if the input url already has a leading slash.
            if (!url.startsWith('/')) {
                // Appends the leading slash if needed. 
                url = '/' + url;
            }

            // Checks if the input url already starts with the base url.
            if (url.startsWith(baseUrl)) {
                // If already contains the base url.
                return url;
            } else {
                // Appends the base url if needed.
                return baseUrl + url;
            }
        } else {
            return url;
        }
    }

    /**
     * Prepares the HttpParams based on the provided parameter object.
     * @param params The provided parameter object.
     * @returns HttpParams instance.
     */
    prepareHttpParams(params: any = {}): HttpParams {
        // Prepares the HttpParams.
        let inputParams = new HttpParams();

        if (params) {
            for (let key in params) {
                inputParams = inputParams.set(key, params[key]);
            }
        }

        return inputParams;
    }

    /**
     * Creates the customized http request header.
     * @returns Headers instance with customized data. 
     */
    createRequestHeader(): HttpHeaders {
        // Sets headers here e.g.
        let headers = new HttpHeaders();
        headers = headers.append('Content-Type', 'application/json');
        headers = headers.append('Accept', 'application/json');

        return headers;
    }

    getText(url: string, params: any = {}): Observable<String> {
        // Appends the base url if needed.
        url = this.combineUrl(this.baseUrl, url);

        // Prepares the HttpParams.
        let inputParams = this.prepareHttpParams(params);

        return this.httpClient.get(url, {
            headers: this.createRequestHeader(),
            responseType: 'text',
            params: inputParams
        });
    }

    /**
     * Gets the remote server data.
     * @param url The remote server relative url. The base url will be appended automatically.
     * @param params The parameters for getting data.
     * @returns The Observable result returned by HttpClient.
     */
    // get<T>(url: string, params: any = {}): Observable<T> {
    //     return this.makeGetRequest<T>(this.baseUrl, url, params);
    // }
    get<T>(url: string, params: any = {}): Observable<T> {
        return this.makeGetRequest<T>(this.baseUrl, url, params);
    }

    /**
     * Gets the remote server data without auto appended base url. It uses the provided url directly.
     * This is suitable for loading local json file or making a request to another remote system url.
     * @param url The remote server relative url. NO base url will be appended automatically.
     * @param params The parameters for getting data.
     * @returns The Observable result returned by HttpClient.
     */
    // getWithoutBaseUrl<T>(url: string, params: any = {}): Observable<T> {
    //     return this.makeGetRequest<T>(null, url, params);
    // }
    getWithoutBaseUrl<T>(url: string, params: any = {}): Observable<T> {
        return this.makeGetRequest<T>('', url, params);
    }

    /**
     * Makes a http get request to remote server by using the provided url. The base url will be auto appended if needed.
     * @param url The remote server relative url. The base url will be appended automatically if needed.
     * @param params The parameters for getting data.
     * @returns The Observable result returned by HttpClient.
     */
    private makeGetRequest<T>(baseUrl: string, url: string, params: any = {}): Observable<T> {
        // Prepares the HttpParams.
        let inputParams = this.prepareHttpParams(params);

        // Appends the base url if needed.
        url = this.combineUrl(baseUrl, url);

        return this.httpClient.get<T>(url, {
            headers: this.createRequestHeader(),
            params: inputParams
        });
    }
}